'  ==========================================================================
'  |                                                                        |
'  | SQLitening Server Exits                                                |
'  |                                                                        |
'  ==========================================================================
'   This is an example Dll which will receive calls from SQLiteningServer at
'   specific exit points.  The term 'Exit' comes from the main process
'   (SQLiteningServer) 'Exiting' to a sub process and then waiting for the
'   return code.  This sub process is a Dll than must be named
'   SQLiteningServerExits.Dll and has one exported entry named AllExits.  This
'   entry accepts all exit calls from the main process.  The sub process will
'   do whatever processing is required and then return a code to the main
'   process.  If the return code is zero then the main process will continue
'   else this code is returned to the calling client as an error.  This sub
'   process must be thread safe, it can access SQLite3.Dll directly using the
'   included macros.  It can not use SQLitening.Dll because it is not thread
'   safe.
'  ==========================================================================
'  PUBLIC DOMAIN SOFTWARE
'  The author or authors of this code dedicate any and all
'  copyright interest in this code to the public domain.
'  Anyone is free to copy, modify, publish, use, compile,
'  sell, or distribute the original code, either in source
'  code form or as a compiled binary, for any purpose,
'  commercial or non-commercial, and by any means.
'  Fred Meier - July 2010
'  ==========================================================================

#Compile Dll "..\Bin\SQLiteningServerExits.Dll"
#Dim All
' DO NOT Include SQLitening.Inc

'============================<[ Equates ]>=============================
' ==========>>> SQLite
%SQLITE3_OK     =   0   '*/ Successful result */
%SQLITE3_BUSY   =   5   '*/ The database file is locked */
%SQLITE3_ROW    = 100   '*/ sqlite3_step() has another row ready */
%SQLITE3_DONE   = 101   '*/ sqlite3_step() has finished executing */
%SQLITE_OPEN_READONLY = &H00000001
%SQLITE_OPEN_READWRITE = &H00000002
%SQLITE_OPEN_CREATE = &H00000004

' ==========>>> Misc
%True = -1
%False = 0
%MaxConnections = 1

'=====================<[ SQLitening Error Codes ]>=====================
'    -7 = No open database
'    -8 = Access denied
'         -- Connect was able to do Tcp Open but was unable to "talk"
'            to SQLitening service. Probable caused by some type of
'            firewall setting or an exit has denied connection.
'         -- Open, Attach, GetFile, or PutFile password check failed or
'            the file is protected.
'    -9 = File does not exist
'   -10 = File error doing open, get, or put
'   -11 = Set locks failed
'   -12 = No changed rows
'   -13 = Invalid column name or number
'   -14 = Invalid set number
'   -15 = Can not use SQL Attach
'   -16 = Can not connect
'         -- Tcp Open failed.
'   -17 = Invalid key or key not found
'         -- Ini GetFile section or entity not found.
'         -- Ini PutFile WritePrivateProfileString winapi failed.
'         -- Encrypt key must be set and must be 16, 24, or 32 bytes.
'   -18 = Error sending or receiving message"
'         -- Prior connect failed, server went away, TCP time-out, or message length error
'   -19 = Invalid string or request
'         -- Uncompressing string which is not compressed.
'         -- String is too big to compress.
'         -- BindDat is invalid.
'         -- RunProc is invalid library or entry.

'=======================<[ SQLite Error Codes ]>=======================
'     0 = Successful result
'     1 = SQL error or missing database
'     2 = Internal logic error in SQLite
'     3 = Access permission denied
'     4 = Callback routine requested an abort
'     5 = The database file is locked
'     6 = A table in the database is locked
'     7 = A malloc() failed
'     8 = Attempt to write a readonly database
'     9 = Operation terminated by sqlite3_interrupt()
'    10 = Some kind of disk I/O error occurred
'    11 = The database disk image is malformed
'    12 = NOT USED. Table or record not found
'    13 = Insertion failed because database is full
'    14 = Unable to open the database file
'    15 = NOT USED. Database lock protocol error
'    16 = Database is empty
'    17 = The database schema changed
'    18 = String or BLOB exceeds size limit
'    19 = Abort due to constraint violation
'         ' Normally caused by trying to add a non unique key
'         ' to an index during an Insert or Update.
'    20 = Data type mismatch
'    21 = Library used incorrectly
'    22 = Uses OS features not supported on host
'    23 = Authorization denied
'    24 = Auxiliary database format error
'    25 = 2nd parameter to sqlite3_bind out of range
'    26 = File opened that is not a database file
'   100 = sqlite_step() has another row ready
'   101 = sqlite_step() has finished executing

'=======================<[ Equates and Types ]>========================
TYPE LIST_ENTRY
    Flink AS LIST_ENTRY PTR
    Blink AS LIST_ENTRY PTR
END TYPE

TYPE RTL_CRITICAL_SECTION_DEBUG
    wType AS WORD
    CreatorBackTraceIndex AS WORD
    CriticalSection AS DWORD  ' actually, CRITICAL_SECTION PTR, but we can not do a circular reference
    ProcessLocksList AS LIST_ENTRY
    EntryCount AS DWORD
    ContentionCount AS DWORD
    Spare(0 TO 1) AS DWORD
END TYPE

TYPE CRITICAL_SECTION
    DebugInfo AS RTL_CRITICAL_SECTION_DEBUG PTR
    ' The following three fields control entering and exiting the critical
    ' section for the resource
    LockCount AS LONG
    RecursionCount AS LONG
    OwningThread AS DWORD    ' from the thread's ClientId->UniqueThread
    LockSemaphore AS DWORD
    SpinCount AS DWORD       ' force size on 64-bit systems when packed
END TYPE
%SQLIte_UTF8      = 1
%SQLite_Transient = -1

' ==========>>> Using Ones
Declare Sub UsingLogIt(rsEntry as String)

'=========================<[ SQLite Declares ]>=========================
Declare Function sqlite3_bind_blob cdecl lib "sqlite3.dll" alias "sqlite3_bind_blob" (byval rhSet as Dword, byval rlPos as Long, byval rsData as Dword, byval rlLen as Long, byval rhZero as Dword) as Long
Declare Function sqlite3_bind_null cdecl lib "sqlite3.dll" alias "sqlite3_bind_null" (byval rhSet as Dword, byval rlPos as Long) as Long
Declare Function sqlite3_bind_text cdecl lib "sqlite3.dll" alias "sqlite3_bind_text" (byval rhSet as Dword, byval rlPos as Long, byval rsData as Dword, byval rlLen as Long, byval rhZero as Dword) as Long
Declare Sub      sqlite3_busy_timeout cdecl lib "sqlite3.dll" alias "sqlite3_busy_timeout" (byval rhDab as Dword, byval rlWaitMS as Long)
Declare Function sqlite3_changes cdecl lib "sqlite3.dll" alias "sqlite3_changes" (byval rhDab as Dword) as Long
Declare Function sqlite3_close cdecl lib "sqlite3.dll" alias "sqlite3_close" (byval rhDab as Dword) as Long
Declare Function sqlite3_column_blob cdecl lib "sqlite3.dll" alias "sqlite3_column_blob" (byval rhSet as Dword, byval rlCol as Long) as Dword
Declare Function sqlite3_column_bytes cdecl lib "sqlite3.dll" alias "sqlite3_column_bytes" (byval rhSet as Dword, byval rlCol as Long) as Long
Declare Function sqlite3_column_count cdecl lib "sqlite3.dll" alias "sqlite3_column_count" (byval rhSet as Dword) as Long
Declare Function sqlite3_column_name cdecl lib "sqlite3.dll" alias "sqlite3_column_name" (byval rhSet as Dword, byval rlCol as Long) as Long
Declare Function sqlite3_column_type cdecl lib "sqlite3.dll" alias "sqlite3_column_type" (byval rhSet as Dword, byval rlCol as Long) as Long
Declare Function sqlite3_create_function cdecl lib "sqlite3.dll" alias "sqlite3_create_function" (byval rhDab as Dword, zName as Asciiz, byval nArg as Long, byval eTextRep as Long, _
                                                                                                  byval pUserData as Dword, byval pFunc as Dword, byval pStep as Dword, byval pFinal as Dword) as Long
Declare Function sqlite3_errcode cdecl lib "sqlite3.dll" alias "sqlite3_errcode" (byval rhDab as Dword) as Long
Declare Function sqlite3_errmsg cdecl lib "sqlite3.dll" alias "sqlite3_errmsg" (byval rhDab as Dword) as Long
Declare Function sqlite3_exec cdecl lib "sqlite3.dll" alias "sqlite3_exec" (byval rhDab as Dword, byval rspStatements as Dword, byval rhZero as Dword, byval rhZero as Dword, byval rhZero as Dword) as Long
Declare Function sqlite3_finalize cdecl lib "sqlite3.dll" alias "sqlite3_finalize" (byval rhSet as Dword) as Long
Declare Function sqlite3_last_insert_rowid cdecl lib "sqlite3.dll" alias "sqlite3_last_insert_rowid" (byval rhDab as Dword) as Quad
Declare Function sqlite3_open_v2 cdecl lib "sqlite3.dll" alias "sqlite3_open_v2" (rzFilename as Asciiz, wrhDab as Dword, byval rlFlags as Long, byval rlNull as Long) as Long
Declare Function sqlite3_prepare_v2 cdecl lib "sqlite3.dll" alias "sqlite3_prepare_v2" (byval rhDab as Dword, byval rspStatement as Dword, byval rlLen as Long, ppVMM as Dword, byval pzTail as Asciiz ptr) as Long
Declare Function sqlite3_reset cdecl lib "sqlite3.dll" alias "sqlite3_reset" (byval rhSet as Dword) as Long
Declare Sub      sqlite3_result_blob cdecl lib "sqlite3.dll" alias "sqlite3_result_blob" (byval sqlite3_context as Dword, byval pzText as Dword, byval nBytes as Long, byval Dword)
Declare Sub      sqlite3_result_text cdecl lib "sqlite3.dll" alias "sqlite3_result_text" (byval sqlite3_context as Dword, byval pzText as Dword, byval nBytes as Long, byval Dword)
Declare Function sqlite3_threadsafe cdecl lib "sqlite3.dll" alias "sqlite3_threadsafe" () as Long
Declare Function sqlite3_step cdecl lib "sqlite3.dll" alias "sqlite3_step" (byval rhSet as Dword) as Long
Declare Function sqlite3_total_changes cdecl lib "sqlite3.dll" alias "sqlite3_total_changes" (byval rhDab as Dword) as Long
Declare Sub      sqlite3_thread_cleanup cdecl lib "sqlite3.dll" alias "sqlite3_thread_cleanup"
Declare Function sqlite3_user_data cdecl lib "sqlite3.dll" alias "sqlite3_user_data" (byval sqlite3_context as Dword) as Dword
Declare Function sqlite3_value_text cdecl lib "sqlite3.dll" alias "sqlite3_value_text" (byval sqlite3_value as Dword) as Dword
Declare Function sqlite3_value_int cdecl lib "sqlite3.dll" alias "sqlite3_value_int" (byval sqlite3_value as Dword) as Dword

'===================<[ WinAPI and Other Declares ]>====================
Declare Sub      InitializeCriticalSection LIB "KERNEL32.DLL" ALIAS "InitializeCriticalSection" (lpCriticalSection AS CRITICAL_SECTION)
Declare Sub      EnterCriticalSection LIB "KERNEL32.DLL" ALIAS "EnterCriticalSection" (lpCriticalSection AS CRITICAL_SECTION)
Declare Sub      LeaveCriticalSection LIB "KERNEL32.DLL" ALIAS "LeaveCriticalSection" (lpCriticalSection AS CRITICAL_SECTION)
Declare Sub      DeleteCriticalSection LIB "KERNEL32.DLL" ALIAS "DeleteCriticalSection" (lpCriticalSection AS CRITICAL_SECTION)

'=============================<[ Macros ]>=============================
' ==========>>> Open
Macro Function slmOpen(rsFileName, rlFlags, whDab)
   Macrotemp llRC
   Local llRC as Long
   llRC = sqlite3_open_v2(rsFileName, whDab, rlFlags or iif&(isfalse (rlFlags and %SQLITE_OPEN_READONLY), %SQLITE_OPEN_READWRITE, 0), 0)
   if isfalse llRC then
      sqlite3_busy_timeout whDab, 10000
   end if
End Macro = llRC

' ==========>>> Prep
Macro Function slmPrep(rhDab, rsStatement, whSet)
   Macrotemp lsA
   Local lsA as String
   lsA = rsStatement
End Macro = sqlite3_prepare_v2(rhDab, strptr(lsA), len(lsA), whSet, 0)

' ==========>>> Step
Macro Function slmStep(rhSet)
End Macro = sqlite3_step(rhSet)

' ==========>>> Finalize
Macro Function slmFinalize(rhSet)
End Macro = sqlite3_finalize(rhSet)

' ==========>>> Finalize No Return Code
MACRO slmFinalizeNoRC(rhSet) = sqlite3_finalize(rhSet)

' ==========>>> Exe
Macro Function slmExe(rhDab, rsStatement)
   Macrotemp lsA
   Local lsA as String
   lsA = rsStatement
End Macro = sqlite3_exec(rhDab, strptr(lsA), 0, 0, 0)

' ==========>>> Bind Blob
Macro Function slmBindBlob(rhSet, rlIndex, rsData)
   Macrotemp lsA
   Local lsA as String
   lsA = rsData
End Macro = sqlite3_bind_blob(rhSet, rlIndex, strptr(lsA), len(lsA), 0)

' ==========>>> Bind Text
Macro Function slmBindText(rhSet, rlIndex, rsData)
   Macrotemp lsA
   Local lsA as String
   lsA = rsData
End Macro = sqlite3_bind_text(rhSet, rlIndex, strptr(lsA), len(lsA), 0)

' ==========>>> Close
Macro Function slmClose(rhDab)
End Macro = sqlite3_close(rhDab)

' ==========>>> Close No Return Code
MACRO slmCloseNoRC(rhDab) = sqlite3_close(rhDab)

' ==========>>> Field Get
Macro Function slmF(rhSet, rlField)
End Macro = peek$(sqlite3_column_blob(rhSet, rlField - 1),  sqlite3_column_bytes(rhSet, rlField - 1))

' ==========>>> Get Field Type
Macro Function slmGetFieldType(rhSet, rlField)
'     Integer=1, Float=2, Text=3, BLOB=4, Null=5
End Macro = sqlite3_column_type(rhSet, rlField - 1)

' ==========>>> Get Insert ID
Macro Function slmGetInsertID(rhDab)
End Macro = sqlite3_last_insert_rowid (rhDab)

' ==========>>> Set Busy Timeout
MACRO slmSetBusyTimeout(rhDab, rlMilliSeconds ) = sqlite3_busy_timeout rhDab, rlMilliSeconds

' ==========>>> Get Error
Macro Function slmGetError(rhDab)
   Macrotemp lzpError
   Local lzpError as Asciiz Ptr
   lzpError= sqlite3_errmsg(rhDab)
End Macro = @lzpError

'============================<[ Globals ]>=============================
' MUST BE THREAD SAFE ---  USE CriticalSection CODE TO UPDATE GLOBALS !!!!

Global guCriticalSection as CRITICAL_SECTION ' Critical section handle
Global glConnectionCount as Long
Threaded tlConnectDenied as Long

'========================<[ Connect Exit #1 ]>=========================
Function ConnectExit(byval rhLogItCodePtr as Dword, _
                     rsData as String) as Long
'  Do whatever is needed.   Return 0 if OK else best to return one
'  of the SQLitening error codes to deny connection.  This example
'  allows only %MaxConnections at one time.  If greater than %MaxConnections
'  then Access denied (-8) is returned.

   ' Check connection count
   if glConnectionCount => %MaxConnections then

      ' Too many so deny
      call dword rhLogItCodePtr using UsingLogIt("Connection count exceeded")
      tlConnectDenied = %True
      function = -8

   else
      ' Enter critical
      EnterCriticalSection guCriticalSection

      ' Bump count
      incr glConnectionCount

      ' Leave critical
      LeaveCriticalSection guCriticalSection

   end if

   ' LogIt for no good reason
   call dword rhLogItCodePtr using UsingLogIt("Exit #1 has run -- TcpFile=" & parse$(rsData, $BS, 1))

End Function

'==========================<[ Disconnect Exit #2 ]>==========================
Sub DisconnectExit(byval rhLogItCodePtr as Dword, _
                   rsData as String)
'  Do whatever is needed.   Return is ignored so this is a Sub.
'  This example will reduce the global connection count.  Note that
'  this rut is called even if connection was denied so reason for the
'  tlConnectDenied threaded flag.

   ' Reduce count if > zero and if we did not deny the connect
   if glConnectionCount > 0 and isfalse tlConnectDenied then

      ' Enter critical
      EnterCriticalSection guCriticalSection

      ' Reduce count
      decr glConnectionCount

      ' Leave critical
      LeaveCriticalSection guCriticalSection

   end if

   ' LogIt for no good reason
   call dword rhLogItCodePtr using UsingLogIt("Exit #2 has run -- TcpFile=" & parse$(rsData, $BS, 1))

End Sub

'=========================<[ Access Exit #3 ]>=========================
Function AccessExit(byval rhLogItCodePtr as Dword, _
                    rsData as String) as Long
'  Do whatever is needed.   Return 0 if OK else best to return one
'  of the SQLitening error codes to deny access.  This example
'  just parses the data and logs the facts.

   Local lsName as String
   Local lsPassword as String
   Local llType as Long
   Local llValue as Long

   ' Parse data
   lsName = parse$(rsData, $BS, 2)
   lsPassword = parse$(rsData, $BS, 3)
   llType = val(parse$(rsData, $BS, 4))
   llValue = val(parse$(rsData, $BS, 5))

   ' Log it for no good reason
   call dword rhLogItCodePtr using UsingLogIt("Exit #3 has run -- TcpFile=" & parse$(rsData, $BS, 1) & "  " &  _
                                              "Access Data is " & _
                                              "Name=" & lsName & "   " & _
                                              "Password=" & lsPassword & "   " & _
                                              "Type=" & hex$(llType) & "   " & _
                                              "Value=" & hex$(llValue))

End Function

'==========================<[ Open Exit #4 ]>==========================
Function OpenExit(byval rhLogItCodePtr as Dword, _
                  rsData as String) as Long
'  Do whatever is needed.   Return 0 if OK else best to return one
'  of the SQLitening error codes to deny open.  This example creates
'  two SQLite custom functions (MyF0 and MyF2) and logs the facts.
'  Using this exit to create cusom functions will only work for remote
'  mode.  You must use a Proc if you want the custom function to work
'  in both local and remote mode.

   Local lhDab as Dword
   Local lsDatabaseFileName as String
   Local lsPassword as String
   Local lzA as asciz * 10

   ' Parse data
   lhDab = val(parse$(rsData, $BS, 1))
   lsDatabaseFileName = parse$(rsData, $BS, 2)
   lsPassword = parse$(rsData, $BS, 3)

   ' Create custom SQLite function called MyF0
   lzA = "MyF0"
   function = sqlite3_create_function(lhDab, lzA, 0, %SQLIte_UTF8, lhDab, codeptr(MyF0), 0, 0)

   ' Create custom SQLite function called MyF2
   lzA = "MyF2"
   function = sqlite3_create_function(lhDab, lzA, 2, %SQLIte_UTF8, lhDab, codeptr(MyF2), 0, 0)

   ' Log it for no good reason
   call dword rhLogItCodePtr using UsingLogIt("Exit #4 has run -- DbHnd=" & format$(lhDab) & "  " &  _
                                              "Database File Name=" & lsDatabaseFileName & "  " &  _
                                              "Password=" & lsPassword)

End Function

' ==========>>> SQLite Custom Function MyF0 CallBack
' This expects 0 parms.
Sub MyF0 cdecl(byval rhContext as Dword, byval rlParmCount as Long, byval rhpParms as Dword ptr)

   Local llRC as Long
   Local lhDab as Dword
   Local lhSet as Dword
   Local lsA as String

   lhDab = sqlite3_user_data(rhContext)
   lsA = "This is a test====="

   ' Insert some records
   300 llRC = slmExe(lhDab, "Insert into T1 values ('Hello666',34562)")
   if llRC then goto ErrorExit
   310 llRC = slmExe(lhDab, "Insert into T1 values ('666',2)")
   if llRC then goto ErrorExit

   ' Insert a record using bind
   ' Prep
   400 llRC = slmPrep(lhDab, "Insert into T1 values (?, ?)", lhSet)
   if llRC then goto ErrorExit
   ' Bind 1
   401 llRC = slmBindBlob(lhSet, 1, "Data1111")
   if llRC then goto ErrorExit
   ' Bind 2
   402 llRC = slmBindText(lhSet, 2, mkl$(123456) & "Data22222")
   if llRC then goto ErrorExit
   ' Step
   403 llRC = slmStep(lhSet)
   if llRC <> %SQLITE3_DONE then goto ErrorExit
   ' Finalize
   404 llRC = slmFinalize(lhSet)
   if llRC then goto ErrorExit

   ' Prep the select statement
   500 llRC = slmPrep(lhDab, "Select * from T1", lhSet)
   if llRC then goto ErrorExit

   ' Step thru the returning records
   do
      llRC = slmStep(lhSet)
      if llRC = %SQLITE3_DONE then exit do
      if llRC <> %SQLITE3_ROW then goto ErrorExit

      ' Get the field data
      lsA &= slmF(lhSet, 1)
      lsA &= slmF(lhSet, 2)

   loop

   'Finalize/close recordset
   600 llRC = slmFinalize(lhSet)
   if llRC then goto ErrorExit

   ResultBack:
   sqlite3_result_blob rhContext, byval strptr(lsA), -1, %SQLite_Transient

   ' Exit
   exit sub

ErrorExit:
   lsA = "Had Error " & format$(llRC)
   goto ResultBack

End Sub

' ==========>>> SQLite Custom Function MyF2 CallBack
' This expects 2 parms:  Parm 1 is an integer, Parm 2 is text.
Sub MyF2 cdecl(byval rhContext as Dword, byval rlParmCount as Long, byval rhpParms as Dword ptr)

   Local lhDab as Dword
   Local lsA as String
   Local lspParm2 as Asciz ptr

   lhDab = sqlite3_user_data(rhContext)
   lspParm2 = sqlite3_value_text(@rhpParms[1])
   lsA = "This is a test.  Parm1=" & format$(sqlite3_value_int(@rhpParms[0])) & "   Parm2=" & @lspParm2 & " Dab=" & format$(lhDab) & "  conut=" & format$(rlParmCount)
   sqlite3_result_blob rhContext, byval strptr(lsA), -1, %SQLite_Transient

End Sub

'========================<[ Start Exit #101 ]>=========================
Function StartExit(byval rhLogItCodePtr as Dword) as Long
'  Do whatever is needed.   You can also do start stuff in LibMain.
'  Return 0 if OK or any not 0 to prevent SQLiteningServer to start.
'  This example just logs that this exit has run.

   ' Log it for no good reason
   call dword rhLogItCodePtr using UsingLogIt("Exit #101 has run")

End Function

'========================<[ Stop Exit #102 ]>=========================
Sub StopExit(byval rhLogItCodePtr as Dword)
'  Do whatever is needed.   You can also do stop stuff in LibMain.
'  Return is ignored so this is a Sub.
'  This example just logs that this exit has run.

   ' Log it for no good reason
   call dword rhLogItCodePtr using UsingLogIt("Exit #102 has run")

End Sub

'===========================<[ All Exits ]>============================
Function AllExits alias "AllExits" (byval rlExit as Long, _
                                    byval rhLogItCodePtr as Dword, _
                                    rsData as String)Export as Long

'   Exit values, when the exit occurs, what is passed in Data, and what
'   are the expected  return values.
'
'       1 = Connnect. Occurs when slConnect is issued.  Before the entry
'           is loged.  Data contains the following $BS delimited values.
'                 1 = Tcp File Number
'                 2 = Socket Number
'                 3 = User Name, if received from client
'                 4 = Computer Name, if received from client
'                 5 = IP Address, if received from client
'           Return zero if OK or non zero to reject the connect.
'
'       2 = Disconnect. Occurs when slDisconnect is issued or a connection is
'           dropped.  Data contains the following $BS delimited values.
'                 1 = Tcp File Number
'                 2 = Socket Number
'                 3 = One of the following result values
'                       57 or 0 = Dropped OK
'                       255     = slDisconnect issued
'                       else    = Dropped -- value is PB err code
'           Return is ignored.
'
'       3 = Access. Occurs when one of the following is issued but before
'           it is actually done:
'              slOpen, slAttach, slGetFile, slPutFile, slRunProc
'           Data contains the following $BS delimited values.
'                 1 = Tcp File Number
'                 2 = File or Proc Name
'                 3 = Pass Word, if received from client
'                 4 = Type as follows:
'                       1 = GetFile
'                       2 = PutFile
'                       4 = Open
'                       8 = Attach
'                      16 = Run Proc
'                 5 = Value and use depends on Type as follows:
'                       Ignore if Type 1 or 2.
'                       Contains the SQLite open flags (Create and ReadOnly) if Type 4.
'                       Contains the open database handle if Type 8.
'
'       4 = Open. Occurs after slOpen one of the following is issued but before
'           it is actually done:
'              slOpen, slAttach, slGetFile, slPutFile, slRunProc
'           Data contains the following $BS delimited values.
'                 1 = Open database handle
'                 2 = Database file Name
'                 3 = Pass Word, if received from client
'
'     101 = Start. Occurs once when SQLiteningServer is starting.  No
'           Data is passed.  Return zero if OK or non zero to not allow
'           SQLiteningServer to start.
'
'     102 = Stop. Occurs once when SQLiteningServer is stopping.  No
'           Data is passed.  Return is ignored.
'
'   LogCodePtr may be called passing a single string containg the data
'   to be added to the log.

   ' Crack the exit number
   select case long rlExit
   case 1      ' Connect
      function = ConnectExit(rhLogItCodePtr, rsData)
   case 2      ' Disconnect
      DisconnectExit rhLogItCodePtr, rsData
   case 3      ' Access
      function = AccessExit(rhLogItCodePtr, rsData)
   case 4      ' Open
      function = OpenExit(rhLogItCodePtr, rsData)
   case 101    ' Start
      function = StartExit(rhLogItCodePtr)
   case 102    ' Stop
      StopExit(rhLogItCodePtr)
   end select

End Function

'============================<[ Lib Main ]>============================
Function LibMain(byval InstDLL    AS LONG, _
                 byval Reason   AS LONG, _
                 byval Reserved AS LONG)AS LONG
' InstDLL is the DLL's instance handle.  This handle is used by the calling
'    application to identify the DLL being called.
' Reason specifies a flag indicating why the DLL entry-point is being called.
'    It can be one of the following values:
'    %DLL_PROCESS_ATTACH=1: Indicates that the DLL is being loaded by another process
'    (a DLL or EXE is loading the DLL).  DLLs can use this opportunity to initialize
'    any instance or global data, such as arrays.
'    %DLL_PROCESS_DETACH=0: Indicates that the DLL is being unloaded or detached from
'    the calling application.  DLLs can take this opportunity to clean up all
'    resources for all threads attached and known to the DLL.
'    %DLL_THREAD_ATTACH=2: Indicates that the DLL is being loaded by a new thread in
'    the calling application.  DLLs can use this opportunity to initialize any thread
'    local storage (TLS).
'    %DLL_THREAD_DETACH=3: Indicates that the thread is exiting cleanly.  If the DLL
'    has allocated any thread local storage, it should be released.
' Reserved specifies further aspects of the DLL initialization and cleanup.  If
'    Reason is %DLL_PROCESS_ATTACH, Reserved is NULL (zero) for dynamic loads
'    and non-NULL for static loads.  If Reason is %DLL_PROCESS_DETACH, Reserved
'    is NULL if LibMain has been called by using the FreeLibrary API call and
'    non-NULL if LibMain has been called during process termination.
' Return: If LibMain is called with %DLL_PROCESS_ATTACH, your LibMain function should
'    return a zero (0) if any part of your initialization process fails or a one (1)
'    if no errors were encountered.  If a zero is returned, Windows will abort and
'    unload the DLL from memory. When LibMain is called with any other value than
'    %DLL_PROCESS_ATTACH, the return value is ignored.

   if Reason = 1 then
      InitializeCriticalSection guCriticalSection
   elseif Reason = 0 then
      DeleteCriticalSection guCriticalSection
   end if
   function = 1
End Function


